home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et3_0-a1.lha / et3 / src / GraphView.C < prev    next >
C/C++ Source or Header  |  1992-06-02  |  13KB  |  610 lines

  1. #ifdef __GNUG__
  2. #pragma implementation
  3. #endif
  4.  
  5. #include "GraphView.h"
  6.  
  7. #include "Class.h"
  8. #include "ObjList.h"
  9. #include "IdDictionary.h"
  10. #include "OrdColl.h"
  11. #include "Dialog.h"
  12. #include "TextItem.h"
  13. #include "Math.h"
  14.  
  15. //---- GraphNode -------------------------------------------------------------
  16.  
  17. NewMetaImpl(GraphNode, TreeNode, (TP(constrainingNodes), TP(nonTreeOutEdges), T(inEdges)));
  18.  
  19. GraphNode::GraphNode(int id, Collection *cp) : TreeNode(id, cp)
  20.     constrainingNodes= 0; 
  21.     nonTreeOutEdges= 0;
  22.     inEdges= 0; 
  23. }
  24.  
  25. GraphNode::~GraphNode()
  26. {
  27.     SafeDelete(nonTreeOutEdges);
  28.  
  29.     // clean up contents of GraphNode to avoid duplicate deletes from 
  30.     // CompositeVObject::~CompositeVObject
  31.     if (Size() > 1) {
  32.     Iter next(GetList());
  33.     next();    // skip first
  34.     Object *op;
  35.     while (op= next())
  36.         GetList()->RemovePtr(op);
  37.     }
  38. }
  39.  
  40. VObject *GraphNode::Image()
  41. {
  42.     if (Size() > 0)
  43.     return At(0);
  44.     return 0;
  45. }
  46.  
  47. int GraphNode::CalcShift()
  48. {
  49.     Point origin= contentRect.origin;
  50.     
  51.     if (InCalcShift()) {
  52.     Warning("CalcShift", "cycle in graph");
  53.     return contentRect.origin.x;
  54.     }
  55.     SetFlag(eGraphInCalc);
  56.     if (!IsPositionSet()) {
  57.     SetFlag(eGraphPosSet); 
  58.     if (constrainingNodes) {
  59.         Iter next(constrainingNodes->MakeIterator());
  60.         GraphNode *gp;
  61.         while (gp= (GraphNode*)next()) 
  62.         origin.x= Math::Max(origin.x, gp->CalcShift());
  63.         //if (origin.x != contentRect.origin.x)
  64.         origin.x += 2*(Gap().x);
  65.     }
  66.     SafeDelete(constrainingNodes);
  67.     }
  68.     if (origin != contentRect.origin)
  69.     SetOrigin(origin);   
  70.         
  71.     ResetFlag(eGraphInCalc);
  72.     return contentRect.origin.x+contentRect.extent.x;
  73. }
  74.  
  75. void GraphNode::AddNonTreeOutEdge(GraphNode *gp)
  76. {
  77.     if (nonTreeOutEdges == 0)
  78.     nonTreeOutEdges= new OrdCollection;
  79.     nonTreeOutEdges->Add(gp);
  80. }
  81.  
  82. void GraphNode::AddConstrainingNode(GraphNode *gp)
  83. {
  84.     if (constrainingNodes == 0)
  85.     constrainingNodes= new OrdCollection;
  86.     constrainingNodes->Add(gp);
  87. }
  88.  
  89. void GraphNode::AddNode(VObject *vp)
  90. {
  91.     Add(vp);
  92. }
  93.  
  94. void GraphNode::Draw(Rectangle r)
  95. {
  96.     Image()->DrawAll(r, FALSE);
  97. }
  98.  
  99. void GraphNode::DrawConnections()
  100. {
  101.     TreeNode::DrawConnections();
  102.     if (nonTreeOutEdges) {
  103.     VObject *image= Image();
  104.     Point p1= image->contentRect.E();
  105.     Iter next(nonTreeOutEdges);
  106.     GraphNode *gp;
  107.     while (gp= (GraphNode*)next()) 
  108.         GrLine(p1, gp->Image()->contentRect.W());
  109.     }
  110. }
  111.  
  112. void GraphNode::Export(OStream &s)
  113. {
  114.     // leave node
  115.     if ((Size() + (nonTreeOutEdges ? nonTreeOutEdges->Size() : 0)) == 1)
  116.     return;
  117.     
  118.     GraphNode *gp;
  119.     int i= 0;
  120.     if (Size() > 0) {
  121.     Iter next1(MakeIterator());
  122.     while (gp= (GraphNode*)next1()) {
  123.         if (i++ == 0) // the image of the node itself
  124.         s << gp->AsString() << ": "; 
  125.         else
  126.         s << gp->Image()->AsString() SP;
  127.     } 
  128.     } 
  129.     if (nonTreeOutEdges) {
  130.     Iter next2(nonTreeOutEdges);
  131.     while (gp= (GraphNode*)next2()) 
  132.         s << gp->Image()->AsString() SP;
  133.     }
  134.     s NL;
  135. }
  136.  
  137. //---- GraphNodeMover -------------------------------------------------------------
  138.  
  139. class GraphNodeMover: public Command {
  140.     GraphView *gvp;
  141.     GraphNode *gnp;
  142.     VObject *item;
  143.     GrCursor oldcursor;
  144.     Point delta;
  145. public:
  146.     GraphNodeMover(GraphView *g, GraphNode *v) : Command(cIdNone, "move node")
  147.     { gvp= g; gnp= v; item= gnp->Image(); delta= 0; }
  148.     void TrackFeedback(Point, Point, bool);
  149.     Command *TrackMouse(TrackPhase, Point, Point, Point);
  150.     void DoIt();
  151.     void UndoIt();
  152. };
  153.  
  154. void GraphNodeMover::TrackFeedback(Point anchorPoint, Point nextPoint, bool)
  155. {
  156.     item->Outline(nextPoint - anchorPoint);
  157. }
  158.  
  159. Command *GraphNodeMover::TrackMouse(TrackPhase tp, Point ap, Point, Point np)
  160. {
  161.     switch (tp) {
  162.     case eTrackPress:
  163.     oldcursor= GrGetCursor();
  164.     break;
  165.     case eTrackMove:
  166.     GrSetCursor(eCrsMoveHand);
  167.     break;
  168.     case eTrackRelease:
  169.     delta= np-ap;
  170.     GrSetCursor(oldcursor);
  171.     break;
  172.     default:
  173.     break;
  174.     }
  175.     return this;
  176.  
  177. }
  178.  
  179. void GraphNodeMover::DoIt()
  180. {
  181.     item->Move(delta);
  182.     gnp->contentRect+= delta;
  183.     gvp->CalcExtent();
  184.     gvp->ForceRedraw();
  185. }
  186.  
  187. void GraphNodeMover::UndoIt()
  188. {
  189.     item->Move(-delta);
  190.     gnp->contentRect-= delta;
  191.     gvp->CalcExtent();
  192.     gvp->ForceRedraw();
  193. }
  194.  
  195. //---- GraphView -----------------------------------------------------------------
  196.  
  197. NewMetaImpl(GraphView, TreeView, (TP(nodes), TP(paths), TP(refs)));
  198.  
  199. GraphView::GraphView(EvtHandler *dp) : TreeView(dp)
  200. {
  201.     nodes= new IdDictionary; 
  202.     connType= eTCDiagonal;
  203.     paths= new OrdCollection;
  204.     refs= new OrdCollection;
  205. }
  206.  
  207. GraphView::~GraphView()
  208. {
  209.     if (nodes) {
  210.     nodes->FreeValues();
  211.     SafeDelete(nodes);
  212.     }
  213.     SafeDelete(paths);
  214.     SafeDelete(refs);
  215. }
  216.  
  217. void GraphView::Draw(Rectangle r)
  218. {
  219.     DictionaryIterator it(nodes);
  220.     register GraphNode *np= 0;
  221.     
  222.     View::Draw(r);
  223.     if (connType != eTCNone) {
  224.     while (np= (GraphNode*)it.NextValue()) 
  225.         np->DrawConnections();
  226.     }
  227.     
  228.     DrawPaths(r);
  229.     DrawReferences(r);
  230.         
  231.     it.Reset();
  232.     while (np= (GraphNode*)it.NextValue()) {
  233.     VObject *vp= np->Image();
  234.     if (vp && vp->contentRect.Intersects(r))
  235.         vp->DrawAll(r, vp == GetSelection());
  236.     }
  237. }
  238.  
  239. void GraphView::SetConnType(TreeConnection ct)
  240. {
  241.     if (ct != eTCNone && ct != eTCDiagonal)
  242.     return;  
  243.     connType= ct;
  244.     ForceRedraw();  
  245. }
  246.  
  247. GraphNode *GraphView::FindNode(Point lp)
  248. {
  249.     DictionaryIterator it(nodes);
  250.     GraphNode *np= 0;
  251.     
  252.     while (np= (GraphNode*)it.NextValue()) {
  253.     VObject *vp= np->Image();
  254.     if (vp->ContainsPoint(lp))
  255.         return np;
  256.     } 
  257.     return 0;  
  258. }
  259.  
  260. Command *GraphView::DoLeftButtonDownCommand(Point lp, Token, int cl)
  261. {
  262.     GraphNode *np= FindNode(lp);
  263.     if (np)
  264.     return new TreeNodeSelector(np, cl);
  265.     return gNoChanges;  
  266. }
  267.  
  268. Command *GraphView::DoMiddleButtonDownCommand(Point lp, Token, int)
  269. {
  270.     GraphNode *np= FindNode(lp);
  271.     if (np)
  272.     return new GraphNodeMover(this, np);
  273.     return gNoChanges;  
  274. }
  275.  
  276. void GraphView::CalcExtent()
  277. {
  278.     DictionaryIterator it(nodes);
  279.     register GraphNode *np= 0;
  280.     Rectangle r;
  281.     
  282.     while (np= (GraphNode*)it.NextValue()) 
  283.     r.Merge(np->Image()->contentRect);
  284.     SetExtent(r.extent+Point(200)); 
  285. }
  286.  
  287. Iterator *GraphView::MakeSubPartsIter(Object *)
  288. {
  289.     AbstractMethod("MakeSubPartsIter");
  290.     return 0;  
  291. }
  292.  
  293. Iterator *GraphView::MakeChildrenIter(Object *op)
  294. {
  295.     return MakeSubPartsIter(op);
  296. }
  297.  
  298. VObject *GraphView::DoCreateRoot()
  299. {
  300.     return new TextItem("Root");
  301. }
  302.  
  303. VObject *GraphView::DoCreateDialog()
  304. {
  305.     return 0;
  306. }
  307.  
  308. VObject *GraphView::AssociatedVObject(Object *op)
  309. {
  310.     GraphNode *gp= (GraphNode*) nodes->AtKey(op);
  311.     if (gp)
  312.     return gp->Image();
  313.     return 0;      
  314. }
  315.     
  316. GraphNode *GraphView::AssociatedGraphNode(Object *op)
  317. {
  318.     return (GraphNode*) nodes->AtKey(op);
  319. }
  320.  
  321. void GraphView::SetGraph(GraphNode *root, bool)
  322. {
  323.     DictionaryIterator it(nodes);
  324.     GraphNode *np= 0;
  325.     
  326.     while (np= (GraphNode*)it.NextValue()) {
  327.     np->SetContainer(this);
  328.     np->Enable();
  329.     }
  330.     // calculate tree layout
  331.     root->CalcExtent();
  332.     root->SetOrigin(GetOrigin());
  333.     it.Reset();
  334.     while (np= (GraphNode*)it.NextValue()) 
  335.     np->CalcShift();
  336.     CalcExtent();
  337.     ForceRedraw();
  338. }
  339.  
  340. void GraphView::EmptyGraph()
  341. {
  342.     SetSelection(0);
  343.     nodes->FreeValues();
  344.     nodes->Empty(0);
  345. }
  346.  
  347. GraphNode *GraphView::BuildGraphDFS(Object *np)
  348. {
  349.     Object *subNode;
  350.     GraphNode *gp;
  351.     
  352.     if (gp= (GraphNode*) nodes->AtKey(np)) 
  353.     return gp;
  354.     
  355.     GraphNode *node= new GraphNode;
  356.     node->AddNode(NodeAsVObject(np));
  357.     nodes->PutAtKeyIfAbsent(node, np); // register node in dictionary
  358.     Iterator *it= MakeSubPartsIter(np);
  359.     
  360.     if (it) {
  361.     Iter next(it);
  362.     
  363.     while (subNode= next()) {            
  364.         // node already occurred hence must be a nonTreeOutEdge
  365.         if (gp= (GraphNode*) nodes->AtKey(subNode)) { // node already occurred, -> nonTreeOutEdge
  366.         node->AddNonTreeOutEdge(gp);
  367.         gp->AddConstrainingNode(node);
  368.         } else {
  369.         gp= BuildGraphDFS(subNode);
  370.         node->AddNode(gp);
  371.         }
  372.         gp->AddInEdge(node);
  373.     }
  374.     }
  375.     return node;    
  376. }   
  377.  
  378. void GraphView::BuildGraphBFS(Object *op)
  379. {
  380.     ObjList q;          // queue for breadth first search
  381.     GraphNode *gnp, *snp;
  382.     Object *subnode, *node;
  383.     
  384.     q.Add(op);
  385.     while (q.Size() > 0) {
  386.     node= q.RemoveFirst();
  387.     if ((gnp= (GraphNode*) nodes->AtKey(node)) == 0) {
  388.         gnp= new GraphNode;
  389.         nodes->PutAtKeyIfAbsent(gnp, node);
  390.         gnp->AddNode(NodeAsVObject(node));
  391.     }
  392.     Iterator *it= MakeSubPartsIter(node);
  393.     if (it) {
  394.         Iter next(it);
  395.         while (subnode= next()) {
  396.         // node was already visited
  397.         if (snp= (GraphNode*)nodes->AtKey(subnode)) {
  398.             gnp->AddNonTreeOutEdge(snp);
  399.             snp->AddConstrainingNode(gnp);
  400.         } else {
  401.             snp= new GraphNode();
  402.             snp->AddNode(NodeAsVObject(subnode));
  403.             gnp->AddNode(snp);
  404.             nodes->PutAtKeyIfAbsent(snp, subnode);
  405.             q.Add(subnode);
  406.         }
  407.         snp->AddInEdge(gnp);
  408.         }
  409.     }
  410.     }
  411. }   
  412.  
  413. GraphNode *GraphView::FindRoot()
  414. {
  415.     OrdCollection *oc= new OrdCollection();    
  416.     DictionaryIterator it(nodes);
  417.     GraphNode *np= 0, *root;
  418.  
  419.     while (np= (GraphNode *)it.NextValue())
  420.     if (np->NumInEdges() == 0)
  421.         oc->Add(np);
  422.         
  423.     if (oc->Size() == 1) {
  424.     root= (GraphNode*)oc->First();
  425.     SafeDelete(oc);
  426.     return root;
  427.     }
  428.     // create artificial root
  429.     VObject *vop= DoCreateRoot();
  430.     oc->AddFirst(vop);
  431.     root= new GraphNode(cIdNone, oc);
  432.     nodes->PutAtKeyIfAbsent(root, vop); 
  433.     return root;
  434. }
  435.  
  436. void GraphView::DrawPaths(Rectangle r)
  437. {
  438.     Iter next(paths);
  439.     GraphPath *gp;
  440.     while (gp= (GraphPath*)next()) 
  441.     gp->Draw(r);
  442. }
  443.  
  444. void GraphView::AddPath(GraphPath *p)
  445. {
  446.     paths->Add(p);
  447.     InvalidateRect(p->BBox());
  448. }
  449.  
  450. GraphPath *GraphView::RemovePath(GraphPath *p)
  451. {
  452.     GraphPath *gp;
  453.     gp= (GraphPath*)paths->RemovePtr(p);
  454.     if (gp)
  455.     InvalidateRect(p->BBox());
  456.     return gp;
  457. }
  458.  
  459. void GraphView::RemoveAllPaths()
  460. {
  461.     paths->FreeAll();
  462.     paths->Empty(0);
  463.     ForceRedraw();
  464. }
  465.  
  466. void GraphView::DrawReferences(Rectangle r)
  467. {
  468.     Iter next(refs);
  469.     GraphReference *gp;
  470.     while (gp= (GraphReference*)next()) 
  471.     gp->Draw(r);
  472. }
  473.  
  474. void GraphView::AddReference(GraphReference *p)
  475. {
  476.     refs->Add(p);
  477.     InvalidateRect(p->BBox());
  478. }
  479.  
  480. GraphReference *GraphView::RemoveReference(GraphReference *p)
  481. {
  482.     GraphReference *gp;
  483.     gp= (GraphReference*)refs->RemovePtr(p);
  484.     if (gp)
  485.     InvalidateRect(p->BBox());
  486.     return gp;
  487. }
  488.  
  489. void GraphView::RemoveAllReferences()
  490. {
  491.     refs->FreeAll();
  492.     refs->Empty(0);
  493.     ForceRedraw();
  494. }
  495.  
  496. //---- GraphPath ------------------------------------------------------------
  497.  
  498. GraphPath::GraphPath(GraphView *g, Collection *n, Ink *i, int w, bool f)
  499. {
  500.     nodes= n;
  501.     free= f;
  502.     gvp= g;
  503.     width= w;
  504.     ink= i;
  505. }
  506.         
  507. GraphPath::~GraphPath()
  508. {
  509.     if (free)
  510.     SafeDelete(nodes);
  511. }
  512.     
  513. void GraphPath::Draw(Rectangle)
  514. {
  515.     Object *op;
  516.     VObject *image;
  517.     Iter next(nodes);
  518.  
  519.     for (int i= 0; op= next(); i++) {
  520.     image= gvp->AssociatedVObject(op);
  521.     if (!image)
  522.         continue;//Error("Draw", "node in GraphPath without representation");
  523.     GrSetPenNormal();
  524.     GrStrokeRect(image->contentRect.Expand(1));
  525.     GrSetPenSize(width);
  526.     GrSetPenInk(ink);
  527.     if (i == 0)
  528.         GrMoveto(image->contentRect.Center());
  529.     else
  530.         GrLineto(image->contentRect.Center());
  531.     }
  532. }
  533.  
  534. Rectangle GraphPath::BBox()
  535. {
  536.     Rectangle r;
  537.     Object *op;
  538.     VObject *image;
  539.     Iter next(nodes);
  540.     while (op= next()) 
  541.     if (image= gvp->AssociatedVObject(op))
  542.         r.Merge(image->contentRect.Expand(4));
  543.     return r;
  544. }
  545.  
  546. //---- GraphReference ------------------------------------------------------------
  547.  
  548. GraphReference::GraphReference(GraphView *g, Object *op, Collection *n, Ink *i, int w, bool f)
  549. {
  550.     nodes= n;
  551.     free= f;
  552.     gvp= g;
  553.     width= w;
  554.     ink= i;
  555.     referto= op;
  556. }
  557.         
  558. GraphReference::~GraphReference()
  559. {
  560.     if (free)
  561.     SafeDelete(nodes);
  562. }
  563.     
  564. void GraphReference::Draw(Rectangle)
  565. {
  566.     Object *op;
  567.     VObject *image, *opimage;
  568.  
  569.     Iter next(nodes);
  570.     opimage= gvp->AssociatedVObject(referto);
  571.     if (!opimage)
  572.     return;
  573.     GrSetPenNormal();
  574.     GrStrokeRect(opimage->contentRect.Expand(1)); 
  575.        
  576.     for (int i= 0; op= next(); i++) {
  577.     image= gvp->AssociatedVObject(op);
  578.     if (!image)
  579.         continue;
  580.     GrSetPenNormal();
  581.     GrStrokeRect(image->contentRect.Expand(1));
  582.     DrawConnection(i, opimage, image);
  583.     }
  584. }
  585.  
  586. void GraphReference::DrawConnection(int, VObject *from, VObject *to)
  587. {
  588.     GrSetPenSize(width);
  589.     GrSetPenInk(ink);
  590.     GrLine(from->contentRect.Center(), to->contentRect.Center());
  591. }
  592.  
  593. Rectangle GraphReference::BBox()
  594. {
  595.     Rectangle r;
  596.     Object *op;
  597.     VObject *image, *opimage;
  598.     Iter next(nodes);
  599.   
  600.     opimage= gvp->AssociatedVObject(referto);
  601.     while (opimage && (op= next())) {
  602.     if (image= gvp->AssociatedVObject(op)) {
  603.         r.Merge(opimage->contentRect.Expand(4));
  604.         r.Merge(image->contentRect.Expand(4));
  605.     }
  606.     }
  607.     return r;
  608. }
  609.